package org.nobject.common.code.describer;

import static org.nobject.common.lang.StringUtils.isEmpty;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.nobject.common.exception.ValidateFaildException;
import org.nobject.common.lang.ClassUtils;

/**
 * DescriberUtils
 *
 * @author bianrongjun
 * @version 1.0
 */
public class DescriberUtils {
	
	/** 
	 * 过滤参数
	 * @param method
	 * @param params
	 */
	public static void filterParams(Method method,List params) throws ValidateFaildException{
		MethodDesc methodDesc	=method.getAnnotation(MethodDesc.class);
		Class[] paramTypes		=method.getParameterTypes();
		if(methodDesc==null) return;
		
		//参数个数为0时不校验，或者不为0时但params为空时不校验
		if(paramTypes.length==0) return;
		else if(methodDesc.params().length==0) return;
		ParamDesc[] paramDescs	=methodDesc.params();
		if(params.size()!=paramDescs.length) throw new RuntimeException(method.getDeclaringClass().getName()+"#"+method.getName()+"的ParamDesc参数不匹配");
		for (int i = 0; i < params.size(); i++) {
			try {
				ParamDescriber pv=getParamDesc(paramDescs[i], paramTypes[i]);
				pv.valide(params.get(i));
			} catch (Exception e) {
				throw new ValidateFaildException(e);
			}
		}
	}
	
	/** 
	 * 获取参数描述
	 * @param desc
	 * @param paramType
	 */
	public static ParamDescriber getParamDesc(ParamDesc desc,Class paramType){
		//TODO Validator可以缓存
		ParamDescriber pd=new ParamDescriber(desc);
		ClassDesc classDesc=(ClassDesc)paramType.getAnnotation(ClassDesc.class);
		if(classDesc!=null){
			pd.subKeyFrom=paramType;
			if(isEmpty(pd.comment)){
				pd.comment=classDesc.comment();
			}
		}
		pd.type=paramType;
		return pd;
	}
	
	/** 
	 * 获取返回描述
	 * @param desc
	 * @param returnType
	 */
	public static ReturnDescriber getReturnDesc(ReturnDesc desc,Class returnType){
		//TODO Validator可以缓存
		if(!returnType.equals(void.class)){
			ReturnDescriber rd=new ReturnDescriber(desc);
			ClassDesc classDesc=(ClassDesc)returnType.getAnnotation(ClassDesc.class);
			if(classDesc!=null){
				rd.subKeyFrom=returnType;
				if(isEmpty(rd.comment)){
					rd.comment=classDesc.comment();
				}
			}
			rd.type=returnType;
			return rd;
		}
		return null;
	}
	
	/** 
	 * toMap
	 * @param method
	 */
	public static Map toMap(Method method){
		MethodDesc methodDesc=(MethodDesc)method.getAnnotation(MethodDesc.class);
		if(methodDesc==null) return null;
		Map m=new HashMap();
		m.put("comment", methodDesc.comment());
		
		//参数
		List params=new LinkedList();
		m.put("params", params);
		Class [] paramTypes		=method.getParameterTypes();
		ParamDesc[] paramDescs	=methodDesc.params();
		
		if(paramDescs.length==paramTypes.length){
			for (int i = 0; i < paramTypes.length; i++) {
				ParamDescriber pd=getParamDesc(paramDescs[i], paramTypes[i]);
				params.add(pd.toMap());
			}
		}
		
		
		//返回
		m.put("return", null);
		ReturnDesc returnDesc	=methodDesc.returns();
		if(returnDesc!=null&&!returnDesc.equals(CNull.class)){
			ReturnDescriber rd=getReturnDesc(returnDesc, method.getReturnType());
			if(rd!=null){
				m.put("return", rd.toMap());
			}
		}
		return m;
	}
	
//	/** 
//	 * 获取Desc
//	 * @param desc
//	 */
//	public static Map toMap(Annotation desc,Class subKeyFrom){
//		Map r=new HashMap();
//		Method[] ms=ClassUtils.getMethods(desc.annotationType());
//		//
//		String key		=getKey(desc);
//		boolean vfield	=getVfield(desc);
//		Class keyFrom	=getKeyFrom(desc);
//		if(keyFrom!=null&&!keyFrom.equals(CNull.class)&&vfield&&!isEmpty(key)){
//			Field f=ClassUtils.getField(keyFrom, key);
//			FieldDesc fieldDesc=(FieldDesc)f.getAnnotation(FieldDesc.class);
//			
//		}
//		
//		
//		for(Method m:ms){
//			Class c=m.getReturnType();
//			Object o=null;
//			try {
//				o=m.invoke(desc, new Object[]{});
//			} catch (Exception e) {
//				//System.out.println(desc.getClass().getName()+"#"+m.getName()+":"+m.getParameterTypes());
//				throw new RuntimeException(e);
//			}
//			
//			//转换Desc类型
//			if(o instanceof Class){
//				o=((Class)o).getName();
//			}
//			if(c.isArray()&&c.getComponentType().getSimpleName().endsWith("Desc")){
//				int l=Array.getLength(o);
//				List subs=new LinkedList();
//				for (int i = 0; i < l; i++) {
//					Object subDesc=Array.get(o,i);
//					subs.add(toMap((Annotation)subDesc,  getKeyFrom(desc)));
//				}
//				o=subs;
//			}
//			r.put(m.getName(), o);
//		}
//		return r;
//	}
	
	public static String getName(Object desc)		{return (String)getAnnotationValue	(desc, "name"		,-1);}
	public static int getIdx(Object desc)			{return (Integer)getAnnotationValue	(desc, "idx"		,-1);}
	public static String getComment(Object desc)	{return (String)getAnnotationValue	(desc, "comment"	,null);}
	public static boolean getUnnull(Object desc)	{return (Boolean)getAnnotationValue	(desc, "unnull"		,false);}
	public static String getValidate(Object desc)	{return (String)getAnnotationValue	(desc, "validate"	,null);}
	public static int getLength(Object desc)		{return (Integer)getAnnotationValue	(desc, "length"		,-1);}
	public static String getMessage(Object desc)	{return (String)getAnnotationValue	(desc, "message"	,null);}
	public static String getKey(Object desc)		{return (String)getAnnotationValue	(desc, "key"		,null);}
	public static Class getKeyFrom(Object desc)		{return (Class)getAnnotationValue	(desc, "keyFrom"	,null);}
	public static Class getSubKeyFrom(Object desc)	{return (Class)getAnnotationValue	(desc, "subKeyFrom"	,null);}
	public static Class getType(Object desc)		{return (Class)getAnnotationValue	(desc, "type"		,null);}
	public static boolean getVfield(Object desc)	{return (Boolean)getAnnotationValue	(desc, "vfield"		,true);}
	public static boolean getFilter(Object desc)	{return (Boolean)getAnnotationValue	(desc, "filter"		,true);}
	public static Object getSubs(Object desc)		{return (Object)getAnnotationValue	(desc, "subs"		,null);}
	public static boolean getEach(Object desc)		{return (Boolean)getAnnotationValue	(desc, "each"		,true);}
	public static boolean getSubAllkeyFrom(Object desc){return (Boolean)getAnnotationValue(desc,"subAllkeyFrom",false);}
	
	
	/** 
	 * getAnnotationValue
	 * @param desc
	 * @param methodName
	 * @param defaultValue
	 * @return
	 */
	public static Object getAnnotationValue(Object desc,String methodName,Object defaultValue){
		try {
			Method m=ClassUtils.getMethod(desc.getClass(),methodName);
			if(m==null) return defaultValue;
			Object r=m.invoke(desc);
			if(CNull.class.equals(r)){
				return null;
			}
			return r;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
